<?php
require dirname(__FILE__).'/../iterator_madness.inc.php';
class CV_OutputFilter{
	protected $stringDecorator = 'CV_OutputFilter_StringDecorator';
	protected $simpleTypeDecorator;
	/**
	 * Returns a new instance for given options. Meant to facilitate a fluent interface.
	 * 
	 * @param array $options 
	 */
	public static function factory( $options ){
		return new self($options);
	}
	/**
	 * @param array $options 
	 */
	public function __construct( $options = array() ){
		if( isset($options['StringDecorator']) ){
			if( !class_exists($options['StringDecorator']) ){
				throw new CV_OutputFilter_Exception( 'value for option StringDecorator needs to be a valid class name' );
			}
			$this->stringDecorator = $options['StringDecorator'];			
		}
		if( isset($options['SimpleTypeDecorator'])  ){
			if( !class_exists($options['SimpleTypeDecorator']) ){
				throw new CV_OutputFilter_Exception( 'value for option SimpleTypeDecorator needs to be a valid class name' );
			}
			$this->simpleTypeDecorator = $options['SimpleTypeDecorator'];			
		}
	}
	/**
	 * @param mixed $value Data to decorate 
	 */
	public function decorate( $value ){
		$type = gettype($value);
		switch( $type ){
			case "boolean":
			case "integer":
			case "double":
			case 'NULL':
				if( isset($this->simpleTypeDecorator) ){
				    return new $this->simpleTypeDecorator( $value );
				} else {
					return $value;
				}
			case "string":
				return new $this->stringDecorator( $value );
			case "array":
				return new CV_OutputFilter_ArrayDecorator( $value, $this );
			case "object":
				switch( true ){
					case $value instanceof CV_OutputFilter_AbstractDecorator:
						return $this->decorate( $value->raw() );
					case $value instanceof ArrayObject:
						return new CV_OutputFilter_ArrayObjectDecorator( $value, $this );
					case $value instanceof Iterator:
						return new SugarDualIteratorIterator( new DecoratingKeyValueIterator(new ArrayIterator($value), $this) );
					default:
						return new CV_OutputFilter_ObjectDecorator( $value, $this );
				}
			default:
				trigger_error( "cannot decorate type: '$type'", E_USER_NOTICE );
				return $value;
		}
	}
	/**
	 * @internal
	 */
	public static function cast_key( $item ){
		if( $item instanceof CV_OutputFilter_Decorator ){
			return $item->cast_key();
		}
	}
	public static function unwrap( $value ){
		if( $value instanceof CV_OutputFilter_AbstractDecorator ){
			$value = $value->raw();
		}
		return $value;
	}
	public static function unwrap_recursive( $value ){
		if( $value instanceof CV_OutputFilter_AbstractDecorator ){
			$value = $value->raw();
		}
		if( is_array($value) ){
			$value = array_map( array('self','unwrap_recursive'), $value );
		}
		return $value;
	}
}